/* -*- mode: objc -*- */

// Card (Card-Profile, Card-Port)
typedef struct pa_card_profile_info2 {
  const char *name;        /* Name of this profile */
  const char *description; /* Description of this profile */
  uint32_t   n_sinks;      /* Number of sinks this profile would create */
  uint32_t   n_sources;    /* Number of sources this profile would create */
  uint32_t   priority;     /* The higher this value is, the more useful this profile is as a default. */
  int        available;
  /* Is this profile available? If this is zero, meaning "unavailable",
   * then it makes no sense to try to activate this profile. If this is
   * non-zero, it's still not a guarantee that activating the profile will
   * result in anything useful, it just means that the server isn't aware of
   * any reason why the profile would definitely be useless. \since 5.0 */
} pa_card_profile_info2;

typedef struct pa_card_port_info {
  const char            *name;          /* Name of this port */
  const char            *description;   /* Description of this port */
  uint32_t              priority;       /* The higher this value is, the more useful this port is as a default. */
  int                   available;      /* A #pa_port_available enum, indicating availability status of this port. */
  int                   direction;      /* A #pa_direction enum, indicating the direction of this port. */
  pa_proplist           *proplist;      /* Property list */
  int64_t               latency_offset; /* Latency offset of the port that gets added to the sink/source latency 
                                           when the port is active. */
  uint32_t              n_profiles;     /* Number of entries in profile array */
  pa_card_profile_info2 **profiles2;    /* Array of pointers to available profiles, or NULL. 
                                           Array is terminated by an entry set to NULL. */
} pa_card_port_info;

typedef struct pa_card_info {
  uint32_t              index;            /* Index of this card */
  const char            *name;            /* Name of this card */
  pa_proplist           *proplist;        /* Property list */
  
  uint32_t              n_ports;          /* Number of entries in port array */
  pa_card_port_info     **ports;          /* Array of pointers to ports, or NULL. 
                                             Array is terminated by an entry set to NULL. */
  
  uint32_t              n_profiles;       /* Number of entries in profile array */
  pa_card_profile_info2 **profiles2;      /* Array of pointers to available profiles, or NULL. 
                                             Array is terminated by an entry set to NULL. */
  pa_card_profile_info2 *active_profile2; /* Pointer to active profile in the array, or NULL. */
  
  uint32_t              owner_module;     /* Index of the owning module, or PA_INVALID_INDEX. */
  const char            *driver;          /* Driver name */
} pa_card_info;

// Types
typedef struct pa_channel_map {
  uint8_t               channels;             /* Number of channels */
  pa_channel_position_t map[PA_CHANNELS_MAX]; /* Channel labels */
} pa_channel_map;

typedef struct pa_cvolume {
  uint8_t     channels;                /* Number of channels */
  pa_volume_t values[PA_CHANNELS_MAX]; /* Per-channel volume */
} pa_cvolume;

typedef struct pa_sample_spec {
  pa_sample_format_t format;   /* The sample format */
  uint32_t           rate;     /* The sample rate. (e.g. 44100) */
  uint8_t            channels; /* Audio channels. (1 for mono, 2 for stereo, ...) */
} pa_sample_spec;

typedef struct pa_format_info {
    pa_encoding_t encoding;   /* The encoding used for the format */
    pa_proplist *plist;       /* Additional encoding-specific properties such as sample 
                                 rate, bitrate, etc. */
} pa_format_info;

// Sink
typedef struct pa_sink_port_info {
  const char *name;         /* Name of this port */
  const char *description;  /* Description of this port */
  uint32_t   priority;      /* The higher this value is, the more useful this port is as a default. */
  int        available;     /* A flags (see #pa_port_available), indicating availability status of this port.*/
} pa_sink_port_info;

typedef struct pa_sink_info {
  const char        *name;                /* Name of the sink */
  uint32_t          index;                /* Index of the sink */
  const char        *description;         /* Description of this sink */
  pa_proplist       *proplist;            /* Property list*/
  //
  uint32_t          card;                 /* Card index, or PA_INVALID_INDEX. */
  //
  pa_sink_port_info *active_port;         /* Pointer to active port in the array, or NULL. */
  uint32_t          n_ports;              /* Number of entries in port array */
  pa_sink_port_info **ports;              /* Array of available ports, or NULL. 
                                             Array is terminated by an entry set to NULL. */
  //
  pa_sample_spec    sample_spec;          /* Sample spec of this sink */
  pa_channel_map    channel_map;          /* Channel map */
  pa_cvolume        volume;               /* Volume of the sink */
  pa_volume_t       base_volume;          /* Some kind of "base" volume that refers 
                                             to unamplified/unattenuated volume 
                                             in the context of the output device. */
  uint32_t          n_volume_steps;       /* Number of volume steps for sinks which 
                                             do not support arbitrary volumes.*/
  int               mute;                 /* Mute switch of the sink */
  //
  pa_usec_t         latency;              /* Length of queued audio in the output buffer. */
  pa_usec_t         configured_latency;   /* The latency this device has been configured to. */
  //
  pa_sink_flags_t   flags;                /* Flags */
  pa_sink_state_t   state;                /* State */
  //
  uint8_t           n_formats;            /* Number of formats supported by the sink. */
  pa_format_info    **formats;            /* Array of formats supported by the sink. */
  //
  uint32_t          monitor_source;       /* Index of the monitor source connected to this sink. */
  const char        *monitor_source_name; /* The name of the monitor source. */
  //
  const char        *driver;              /* Driver name */
  uint32_t          owner_module;         /* Index of the owning module, or PA_INVALID_INDEX. */
} pa_sink_info;

// Sink Input
typedef struct pa_sink_input_info {
  uint32_t       index;            /* Index of the sink input */
  const char     *name;            /* Name of the sink input */
  uint32_t       client;           /* Index of the client this sink input belongs to, or PA_INVALID_INDEX. */
  uint32_t       sink;             /* Index of the connected sink */
  const char     *driver;          /* Driver name */
  uint32_t       owner_module;     /* Index of the module this sink input belongs to, or PA_INVALID_INDEX. */
  
  pa_sample_spec sample_spec;      /* The sample specification of the sink input. */
  const char     *resample_method; /* The resampling method used by this sink input. */
  pa_channel_map channel_map;      /* Channel map */
  pa_cvolume     volume;           /* The volume of this sink input. */
  int            mute;             /* Stream muted */
  int            corked;           /* Stream corked */
  int            has_volume;       /* Stream has volume. 
                                      If not set, then the meaning of this struct's volume member is unspecified. */
  int            volume_writable;  /* The volume can be set. 
                                      If not set, the volume can still change even though clients can't control the volume. */
  
  pa_format_info *format;          /* Stream format information. \since 1.0 */
  pa_usec_t      buffer_usec;      /* Latency due to buffering in sink input, see pa_timing_info for details. */
  pa_usec_t      sink_usec;        /* Latency of the sink device, see pa_timing_info for details. */
  pa_proplist    *proplist;        /* Property list */
} pa_sink_input_info;

// Source
typedef struct pa_source_info {
  const char          *name;                 /* Name of the source */
  uint32_t            index;                 /* Index of the source */
  const char          *description;          /* Description of this source */
  pa_proplist         *proplist;             /* Property list */
  //
  uint32_t            card;                  /* Card index, or PA_INVALID_INDEX. */
  //
  pa_source_port_info *active_port;          /* Pointer to active port in the array, or NULL. */
  uint32_t            n_ports;               /* Number of entries in port array. */
  pa_source_port_info **ports;               /* Array of available ports, or NULL. 
                                                Array is terminated by an entry set to NULL. */
  //
  pa_sample_spec      sample_spec;           /* Sample spec of this source */
  pa_channel_map      channel_map;           /* Channel map */
  pa_cvolume          volume;                /* Volume of the source */
  pa_volume_t         base_volume;           /* Some kind of "base" volume that refers 
                                                to unamplified/unattenuated volume in the context 
                                                of input device. */
  uint32_t            n_volume_steps;        /* Number of volume steps for sources which 
                                                do not support arbitrary volumes. */
  int                 mute;                  /* Mute switch of the sink */
  //
  pa_usec_t           latency;               /* Length of filled record buffer of this source. */
  pa_usec_t           configured_latency;    /* The latency this device has been configured to. */
  //
  pa_source_flags_t   flags;                 /* Flags */
  pa_source_state_t   state;                 /* State */
  //
  uint8_t             n_formats;             /* Number of formats supported by the source. */
  pa_format_info      **formats;             /* Array of formats supported by the source. */
  
  uint32_t            monitor_of_sink;       /* If this is a monitor source, the index of the 
                                                owning sink, otherwise PA_INVALID_INDEX */
  const char          *monitor_of_sink_name; /* Name of the owning sink, or NULL. */
  
  const char          *driver;               /* Driver name */
  uint32_t            owner_module;          /* Owning module index, or PA_INVALID_INDEX. */
} pa_source_info;

// Source Output

// Client
typedef struct pa_client_info {
  uint32_t    index;        /* Index of this client */
  const char  *name;        /* Name of this client */
  
  uint32_t    owner_module; /* Index of the owning module, or PA_INVALID_INDEX. */
  const char  *driver;      /* Driver name */
  pa_proplist *proplist;    /* Property list */
} pa_client_info;

// Stream
typedef struct pa_ext_stream_restore_info {
  const char     *name;       /* Identifier string of the stream. 
                                 A string like "sink-input-by-role:" or similar followed 
                                 by some arbitrary property value. */
  pa_channel_map channel_map; /* The channel map for the volume field */
  pa_cvolume     volume;      /* The volume of the stream when it was seen last */
  const char     *device;     /* The sink/source of the stream when it was last seen */
  int            mute;        /* The boolean mute state of the stream when it was last seen */
} pa_ext_stream_restore_info;

/*
  Use cases
*/

/* Mixer */
{ // Initial steps:
  // 1. Get SinkInput, SourceOutput, SavedStreams lists.
  // 2. Display list of: "System Sounds", sink inputs with clients for "Playback" mode.
  // 3. Show Sink with properties (profiles, ports, mute, volume) of selected
  //    SinkInput or SavedStream.
  // Events:
  // - Update list if sink inputs list was changed.
  // - Update properties for selected SinkInput and displayed Sink (volume, mute, profile, port).
  // Actions:
  // - Change volume, mute of sink inputs or source outputs.
  // - Change volume, balance, mute of sink.
  // - Change active profile of card and port of sink.
}
// Mixer with SoundKit
{
  id      server = [NXSoundServer initOnHost:nil withName:@"My Mixer"];
  NSArray *soundStreams = [server streams]; // access to: sink input or source output, stream, client
  NSArray *soundOuts = [server outs];       // access to: sink, server (card, server)
  NSArray *soundIns = [server ins];         // access to: source, server (card, server)
}

/* Simple application */
{ // Steps:
  // 1. Create new stream to play with default output, port and profile.
  // 2. Send bytes of sound to created stream.
  // 3. Pause, mute, change volume and balance.
}
/* Advanced application */
{ // Actions:
  // - Create new stream to play with default output, port and profile.
  // - Change stream profile and port of output.
  // - Send bytes of sound to created stream.
  // - Pause, mute, change volume and balance.
}

/* Player with SoundKit */
{
  NXSoundOut        *soundOut;
  NXSoundStream     *soundStream;
  NXSoundParameters *soundParams;
  
  soundOut = [[NXSoundOut alloc] initOnHost:nil withName:@"Player"];
  soundParams = [NXSoundParameters new];
  soundStream = [[NXSoundStream alloc] initOnDevice:soundOut
                                     withParameters:soundParams];

  [soundStream sendBytes:filePath];
  [soundStream volume];
  [soundStream setVolume:(CGFlloat *)left :(CGFloat *):right];
  [soundStream mute:(BOOL)isMute];
  [soundStream isMute];
  
  [soundStream play];
  [soundStream pause];
  [soundStream resume];
  [soundStream stop];

  /* Advanced: manipulations with Card and Sink - changes are applied for all apps/clients */
  [soundOut profiles];
  [soundOut activeProfile];
  [soundOut setActiveProfile:(NSString *)profileName]; // Changes sound profile for all apps
  [soundOut ports];
  [soundOut activePort];
  [soundOut setActivePort:(NSString *)portName]; // Changes sound profile for all apps
  [soundOut volume];
  [soundOut setVolume];
}
